package org.javahispano.javacup.tacticas_aceptadas.FGR.javacup2009.gallegux.javacup2009.canelaenrama;


import org.javahispano.javacup.tacticas_aceptadas.FGR.javacup2009.gallegux.javacup2009.canelaenrama.ed.DoubleDouble;

import java.awt.Polygon;
import java.util.ArrayList;
import java.util.List;
//import java.io.IOException;
//import java.util.logging.Level;
//import java.util.logging.Logger;
//import org.javahispano.javacup.tacticas.canelaenrama.log.GFileHandler;
import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;


public class CanelaTactica  
{
	
	private static final int TODOS = 0;
	private static final int EXCL_POR = 1;
	
	// VARIABLES
	
	List<Comando> comandos = null;
	
	// variables evolucion del juego, el valor debe cambiar en cada iteracion
	InfoEquipo eqMio, eqRival;
	
	double angBalonAnterior = 0;
	double angBalonActual = 0;
	double distBalonPorteria = 0;
	double angBalonPorteria = 0;
	Posicion posBalonAnterior = new Posicion(0,0);
	Posicion posBalonActual = null;
	boolean balonGolpeado = false;
	boolean golpeeYo = false, golpeoRival = false;
	int iteracionesSaco = 0;
	UltimoGolpeo ultimoGolpeo = null;
	
	public static int iteracionPartido = 0;
	int iteracionPartidoAnterior = 0;


	// variables de la tactica
	TrayectoriaBalon trayectoriaBalon = null;
	Marcajes marcajes = null;
	Tiros TIROS_ALTOS = null;
	ProgramaMovimientoJugador progMovJug = null;
	
	// para ahorrar tiempo
	PosicionesIniciales posiciones = new PosicionesIniciales();
	
	
	//Logger log = Logger.getLogger(getClass().getName());
	
	
	
	// desarrollo
//	public CanelaTactica()
//	{
//		try {
//			Util.removeLoggingHandlers();
//			Logger.getLogger("").addHandler(new GFileHandler("log.txt"));
//
//			TIROS_ALTOS = new Tiros();
//			marcajes = new Marcajes();
//			
//			precalcularTrayectorias();
//			
//			comandos = new ArrayList<Comando>(CTE.ITERACIONES * 2);
//		}
//		catch (IOException e) {
//			e.printStackTrace();
//		}
//	}
	
	
	// consurso
	public CanelaTactica()
	{
			TIROS_ALTOS = new Tiros();
			marcajes = new Marcajes();
			
			precalcularTrayectorias();
			
			comandos = new ArrayList<Comando>(CTE.ITERACIONES * 2);
	}
	
	
	
	
	
	public List<Comando> getComandos(SituacionPartido situacionPartido)
	{
		// basico
		iteracionPartido = situacionPartido.iteracion();
		comandos.clear();
		
		// variables de una sola iteracion 
		boolean cambioTrayectoria = false, atacamos, balonCampoContrario, saqueCentro = false, tengoBalon = false, tienenBalon = false;
		ProgramaMovimientoJugador jtMio = null, jtRival = null, jtMioNoPortero = null;
		Posicion posPortero = CTE.POS_REPOSO_PORTERO;
		
		// solo se ejecuta una vez
		if (eqRival == null) {
			eqMio = new InfoEquipo(situacionPartido.detalleMisJugadores());
			eqRival = new InfoEquipo(situacionPartido.detalleJugadoresRivales());
		}
		
		// actualizamos datos equipos
		eqMio.setPosiciones(situacionPartido.misJugadores());
		eqRival.setPosiciones(situacionPartido.rivales());
		eqMio.setPuedenRematar(situacionPartido.puedenRematar());
		eqRival.setPuedenRematar(situacionPartido.puedenRematarRival());

		// asignaciones, actualizaciones de variables
		posBalonActual = situacionPartido.balon();
		angBalonActual = posBalonAnterior.angulo(posBalonActual);
		distBalonPorteria = posBalonActual.distancia(CTE.PTO_CENTRO_PORTERIA_RIVAL);
		angBalonPorteria = posBalonActual.angulo(CTE.PTO_CENTRO_PORTERIA_RIVAL);
	
		
		//log.info("ite: " + posBalonActual + " dist.B.P: " + distBalonPorteria + "  saques? " + situacionPartido.saco() + " " + situacionPartido.sacaRival() + "  marcajes: " + marcajes);
		
		// detectamos si ha habido gol
		if (saqueCentro = (eqMio.goles != situacionPartido.golesPropios() || eqRival.goles != situacionPartido.golesRival())) {
			// deshacemos marcajes
			marcajes.reset();
			eqMio.goles = situacionPartido.golesPropios();
			eqRival.goles = situacionPartido.golesRival();
			progMovJug = null;
			trayectoriaBalon = null;
			balonGolpeado = false;
			//log.info("GOL!!!  " + eqMio.goles + "-" + eqRival.goles);
		}
		
		if (situacionPartido.saco() || situacionPartido.sacaRival()) {
			trayectoriaBalon = null;
			balonGolpeado = false;
		}
		if (situacionPartido.saco()) {
			iteracionesSaco++;
		}
		else {
			iteracionesSaco = 0;
		}
		
		
		
		// posesion de balon //
		
		if (golpeeYo && !golpeoRival) {
			eqMio.posesion = eqMio.posesion + ((posBalonActual.getY() > 0) ? 2 : 1);
		}
		else if (!golpeeYo && golpeoRival) {
			eqRival.posesion = eqRival.posesion + ((posBalonActual.getY() <0) ? 2 : 1);
		}
		else if (golpeeYo && golpeoRival) {
			// vemos si la pelota va mas o menos donde la mandamos
			double angIni = Util.normalizarAngulo(ultimoGolpeo.angHorizontal - eqMio.errorAngular[ultimoGolpeo.jugador] / 2);
			double angFin = Util.normalizarAngulo(ultimoGolpeo.angHorizontal + eqMio.errorAngular[ultimoGolpeo.jugador] / 2);
			if (Util.anguloEstaEn(angBalonActual, angIni, angFin)) {
				eqMio.posesion = eqMio.posesion + ((posBalonActual.getY() > 0) ? 2 : 1);
			}
			else {
				eqRival.posesion = eqRival.posesion + ((posBalonActual.getY() <0) ? 2 : 1);
			}
		}
		else {
			// no cambia nada
		}

		golpeeYo = false;
		golpeoRival = false;
		ultimoGolpeo = null;
		
		
		
		// hay cambio en la trayectoria ??
		//log.info("ang.act: " + angBalonActual + "    ang.ant: " + angBalonAnterior);
		if (balonGolpeado || 
				!saqueCentro && !situacionPartido.saco() && !situacionPartido.sacaRival() && 
				posBalonAnterior != null && Math.abs(angBalonActual - angBalonAnterior) > CTE.ANG_DESVIACION_TRAYECTORIA) {
			//calculamos la nueva trayectoria del balon
			trayectoriaBalon = new TrayectoriaBalon(posBalonAnterior, posBalonActual, situacionPartido.alturaBalon());
			cambioTrayectoria = true;
		}
		
		
		tengoBalon = eqMio.puedeRematar.length > 0 && sobreElBalon(eqMio, posBalonActual);
		tienenBalon = eqRival.puedeRematar.length > 0;
		atacamos = posBalonActual.getY() > posBalonAnterior.getY() || (tengoBalon && !tienenBalon);
		balonCampoContrario = posBalonActual.getY() > 0;
		
		
		
		// MARCAJES
		// detectamos los nuevos jugadores a marcar
		for (int i = 10; i > 0 && eqRival.posAnterior != null; i--) {
			if (eqRival.posActual[i].getY() < CTE.LINEA_MARCAJE && 
					eqRival.posAnterior[i] != null && eqRival.posAnterior[i].getY() >= CTE.LINEA_MARCAJE) {
				// un jugador rival ha entrado en nuestro campo, a por el !!!
				marcajes.nuevoMarcajeRival(i, eqRival.posActual[i], eqMio.posActual);
			}
			else if (eqRival.posActual[i].getY() >= CTE.LINEA_MARCAJE && 
					eqRival.posAnterior[i] != null &&  eqRival.posAnterior[i].getY() < CTE.LINEA_MARCAJE) {
				if (marcajes.estaMarcado(i)) marcajes.eliminaMarcajeRival(i);
			}
		}

		
		// MOVIMIENTOS

		// por defecto vamos a colocar a los jugadores en su posicion
		for (int i = 0; i < CTE.NUM_JUGADORES; i++) {
			comandos.add(new ComandoIrA(i, posiciones.getNormal()[i]));
		}
		
		
		if (situacionPartido.sacaRival()) { // saque de banda o de puerta
			anadirComandosMarcajes();
			anadirComandosMolestarNoMarcados();
		}
		
		if (atacamos && balonCampoContrario) {
			// si atacamos acercamos los jugadores
			acercarJugadoresAlBalon();
			comandos.add(new ComandoIrA(eqMio.indicePortero, Constantes.penalInf));
		}
		else if (atacamos && !balonCampoContrario) {
			acercarJugadoresAlBalon();
			comandos.add(new ComandoIrA(eqMio.indicePortero, CTE.POS_REPOSO_PORTERO));
		}
		else if (!atacamos && balonCampoContrario) { // defendemos
			// ponemos los comandos de los marcajes
			anadirComandosMarcajes();
			comandos.add(new ComandoIrA(eqMio.indicePortero, CTE.POS_REPOSO_PORTERO));
		}
		else if (!atacamos && !balonCampoContrario) {
			// ponemos los comandos de los marcajes
			anadirComandosMarcajes();

			// que' hace el portero
			if (trayectoriaBalon != null && direccionGol(posBalonActual, angBalonActual)) {
				// si va a gol, lo colocamos
				posPortero = getInterseccion(posBalonActual, angBalonActual, CTE.PTO_LINEA_POR_IZQ, CTE.PTO_LINEA_POR_DER);
			}
			else if (posBalonActual.getY() <= -CTE.MITAD_LARGO_CAMPO+CTE.DIST_PORTERO_LINEA_GOL) {
				if (posBalonActual.getX() > CTE.MITAD_LARGUERO) {
					posPortero = CTE.POS_POR_DER;
				}
				else if (posBalonActual.getX() < -CTE.MITAD_LARGUERO) {
					posPortero = CTE.POS_POR_IZQ;
				}
			}
			else { // lo colocamos lo mejor posible
				posPortero = Posicion.Interseccion(posBalonActual, CTE.PTO_CENTRO_MI_PORTERIA, CTE.PTO_LINEA_POR_IZQ, CTE.PTO_LINEA_POR_DER);
			}
			comandos.add(new ComandoIrA(eqMio.indicePortero, posPortero));
		}
		
		
		if (cambioTrayectoria && trayectoriaBalon.getPosiciones().size() > 0) {
			//log.info("cambio trayectoria");

			List<PosicionBalon> futurasPosiciones = trayectoriaBalon.getPosiciones();
			PosicionBalon posBalonFutura = null;
			Posicion posFuera = null; // posicion del balon si sale fuera
			ProgramaMovimientoJugador[] mejoresMios;
			progMovJug = null; // reset
			
			for (int i = 0; progMovJug == null && posFuera == null && i < futurasPosiciones.size(); i++) {
				// recorremos todas las posiciones de la trayectora, hasta que se coga o salga fuera
				posBalonFutura = futurasPosiciones.get(i);
				////log.info("futura iteracion +" + (i+1) + "  " + posBalonFutura);
				
				if (!posBalonFutura.isDentroCampo()) {
					posFuera = posBalonFutura.getPosicion();
					progMovJug = taparSaque(posBalonFutura.getPosicion(), eqMio.posActual);
				}
				else if (posBalonFutura.isParablePortero()) {
					mejoresMios = calcularMejoresJugadores(posBalonFutura, eqMio, iteracionPartido, iteracionPartido+i+1);
					jtMio = mejoresMios[TODOS];
					jtMioNoPortero = mejoresMios[EXCL_POR];
					jtRival = calcularMejoresJugadores(posBalonFutura, eqRival, iteracionPartido, iteracionPartido+i+1)[TODOS];
					
					if (jtMio.iteracionesHastaPosicion > jtRival.iteracionesHastaPosicion) {
						jtMio = jtMioNoPortero;
					}
					if (jtMio.iteracionesHastaPosicion <= i+1) {
						progMovJug = new ProgramaMovimientoJugador(jtMio);
					}
				}
			} // fin recorrido posiciones
		} // fin cambio de trayectoria			

		
		// si el balon no se mueve --> se trata de un saque
		if (posBalonActual.equals(posBalonAnterior)) {
			if (situacionPartido.sacaRival()) {
				comandos.add(taparSaque(posBalonActual, eqMio.posActual).getComando());
				progMovJug = null;
			}
			else if (situacionPartido.saco()) {
				// saco -> movemos al jugador mas cercano
				// TODO: mirar si el que saca es el portero
				comandos.add(new ComandoIrA(posBalonActual.indiceMasCercano(eqMio.posActual), posBalonActual));
				progMovJug = null;
			}
			else {
				comandos.add(new ComandoIrA(posBalonActual.indiceMasCercano(eqMio.posActual), posBalonActual));
				progMovJug = null;
			}
		}
		else if (balonCasiParado(posBalonAnterior, posBalonActual)) {
			PosicionBalon pb = new PosicionBalon(posBalonActual);
			ProgramaMovimientoJugador[] mejoresMios = calcularMejoresJugadores(pb, eqMio, iteracionPartido, iteracionPartido);
			jtMio = mejoresMios[TODOS];
			jtRival = calcularMejoresJugadores(pb, eqRival, iteracionPartido, iteracionPartido)[TODOS];
			if (jtMio.jugador == eqMio.indicePortero && jtMio.iteracionesHastaPosicion >= jtRival.iteracionesHastaPosicion) {
				jtMio = mejoresMios[1];
			}
			comandos.add(jtMio.getComando());
			progMovJug = null;
		}
		
		if (progMovJug != null) {
			//log.info("--> progMovJug: " + progMovJug + " pos.act: " + eqMio.posActual[progMovJug.jugador]);
			comandos.add(progMovJug.getComando());
		}
		
		
		
		/////////////
		// GOLPEOS //
		/////////////
		
		balonGolpeado = false;
		
		if (iteracionesSaco == 0 || iteracionesSaco == Constantes.ITERACIONES_SAQUE-1 || eqMio.posicionesIguales()) {
			int jugQueTieneElBalon = getJugTieneBalon(eqMio.puedeRematar, eqRival.puedeRematar);
			int futuroJugador;
			//log.info("pueden rematar: " + Util.toString(eqMio.puedeRematar) + " " + jugQueTieneElBalon + " " + Util.toString(eqRival.puedeRematar));
			PaseAnalizado paseAnalizado = null;
			Posicion posAvance;
			
			if (eqRival.puedeRematar.length > 0) {
				//log.info("balon compartido");
			}
			
			for (int j = 0; j < eqMio.puedeRematar.length; j++) {
				int jugador = eqMio.puedeRematar[j];
				paseAnalizado = null;
				posAvance = null;
				//log.info("analizamos remate " + j);
				
				if (jugador != eqMio.indicePortero) {
					
					if (distBalonPorteria < 20 && buenAnguloTiro()) {  // si podemos tirar tiramos
						anadirComandosTiro(jugador);
						// TODO: si el portero no se situa debajo buscar baselina
					}
					else if (jugQueTieneElBalon == jugador) { // el balon lo tiene solo mi jugador
						if (isPartidoFavorable()) {
							// si podemos avanzar, no calculamos pases 
							if ((posAvance = calcularPosicionAvance(posBalonActual, jugador)) != null) {
								anadirComandosAvanzar(jugador, posAvance);
							}
							else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null && 
									paseAnalizado.porcentajeFavor > 0.85) {
								anadirComandosPaseAnalizado(jugador, paseAnalizado);
							}
							else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria + CTE.ANG_180)) != null && 
									paseAnalizado.porcentajeFavor > 0.85) {
								anadirComandosPaseAnalizado(jugador, paseAnalizado);
							}
							else if ((futuroJugador = buscarPaseFacil(jugador, true)) != -1) {
								anadirComandosPaseSimple(jugador, futuroJugador);
							}
							else { // mal asunto
								anadirComandosTiroLejano(jugador);
							}
						}
						else { // partido no favorable
							if (posBalonActual.getY() > 19) { // en posiciones ofensivas
								// hay que arriesgar
								if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null && paseAnalizado.porcentajeFavor > 0.80) {
									anadirComandosPaseAnalizado(jugador, paseAnalizado); 
								}
								else if ((posAvance = calcularPosicionAvance(posBalonActual, jugador)) != null) {
									anadirComandosAvanzar(jugador, posAvance);
								}
								else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria + CTE.ANG_180)) != null && 
										paseAnalizado.porcentajeFavor > 0.85) {
									// pase para atras, mal asunto, defienden bien
									anadirComandosPaseAnalizado(jugador, paseAnalizado); 
								}
								else if ((futuroJugador = buscarPaseFacil(jugador, true)) != -1) {
									anadirComandosPaseSimple(jugador, futuroJugador);
								}
								else { // mal asunto
									anadirComandosTiroLejano(jugador);
								}
							}
							else {
								if ((posAvance = calcularPosicionAvance(posBalonActual, jugador)) != null) {
									anadirComandosAvanzar(jugador, posAvance);
								}
								else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null && 
										paseAnalizado.porcentajeFavor > 0.85) {
									anadirComandosPaseAnalizado(jugador, paseAnalizado); 
								}
								else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria + CTE.ANG_180)) != null && 
										paseAnalizado.porcentajeFavor > 0.90) {
									// pase para atras, mal asunto, defienden bien
									anadirComandosPaseAnalizado(jugador, paseAnalizado); 
								}
								else if ((futuroJugador = buscarPaseFacil(jugador, true)) != -1) {
									anadirComandosPaseSimple(jugador, futuroJugador);
								}
								else { // mal asunto
									anadirComandosTiroLejano(jugador);
								}
							}
						}
					}
					else { // el balon lo comparte mi jugador con un rival, chutamos ya que si avanzamos nos la pueden quitar
						if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null) {
							anadirComandosPaseAnalizado(jugador, paseAnalizado); 
						}
						else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria + CTE.ANG_180)) != null) {
							anadirComandosPaseAnalizado(jugador, paseAnalizado); // pase para atras, pero mejor eso que perderla
						}
						else if ((futuroJugador = buscarPaseFacil(jugador, true)) != -1) {
							anadirComandosPaseSimple(jugador, futuroJugador);
						}
						else {
							anadirComandosTiroLejano(jugador);
						}
					}
				}
				else { // el balon lo tiene el portero
					if (jugQueTieneElBalon == jugador) { 
						if (CTE.PTO_CENTRO_MI_PORTERIA.distancia(eqMio.posActual[eqMio.indicePortero]) < 10 &&
								(posAvance = calcularPosicionAvance(posBalonActual, jugador)) != null ) {
							anadirComandosAvanzar(jugador, posAvance);
						}
						else if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null && paseAnalizado.porcentajeFavor > 0.75) {
							anadirComandosPaseAnalizado(jugador, paseAnalizado);
						}
						else if ((futuroJugador = buscarPaseFacil(jugador, true)) != -1) {
							anadirComandosPaseSimple(jugador, futuroJugador);
						}
						else {
							anadirComandosDespejar(eqMio.indicePortero);
						}
					} 
					else { // el balon lo comparte el portero con un rival !!!
						if ((paseAnalizado = buscarMejorPase(jugador, angBalonPorteria)) != null && paseAnalizado.porcentajeFavor > 0.65) {
							anadirComandosPaseAnalizado(jugador, paseAnalizado);
						}
						else {
							anadirComandosDespejar(eqMio.indicePortero);
						}
					}
				}
			} // fin bucle golpeos
		} // fin generar golpeos
			
		
		// analizamos los golpeos del Rival
		for (int i = 0; i < eqRival.puedeRematar.length; i++) {
			//log.info("NUEVO ultimo_golpeo_rival=" + eqRival.puedeRematar[i]);
			eqRival.setUltimoGolpeo(eqRival.puedeRematar[i]);
			balonGolpeado = true;
			golpeoRival = true;
			// TODO: detectar si avanzan con el balon
		}
		
		
		//-----------------------------------
		// acualizamos las variables internas
		//-----------------------------------
		posBalonAnterior = new Posicion(situacionPartido.balon());
		angBalonAnterior = angBalonActual;
		iteracionPartidoAnterior = iteracionPartido;
		//
		
		
//		if (iteracionPartido == 100) {
//			//log.info(""); eqRival.posesion = 100000;
//		}
		
		return comandos;
	}
	

	
	
	
	////////////////////////////////////////////////////////////////////////
	// METODOS DE A�ADIR COMANDOS///////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////
	
	
	/**
	 * Acerca los jugadores propios al balon
	 * @param comandos
	 */
	private void acercarJugadoresAlBalon()
	{
		int[] divisoresDist = new int[] {/*por*/1, 4,4,4, 3,3, 2,2, 3,3,3};
		Posicion posJugNormal = null, posJugAchique = null;
		int dx, dy;
		
		for (int i = 1; i < CTE.NUM_JUGADORES; i++) {
			posJugNormal = posiciones.getAchique()[i];
			
			dx = (int) (posBalonActual.getX() - posJugNormal.getX());
			dy = (int) (posBalonActual.getY() - posJugNormal.getY());
			
			dx = dx / 4;
			dy = dy / divisoresDist[i];
			
			posJugAchique = posJugNormal.moverPosicion(dx, dy);
			
			comandos.add(new ComandoIrA(i, posJugAchique));
		}
	}
	
	
	
	private void anadirComandosMarcajes()
	{
		Posicion posMarcaje, posRival;
		// El marcador se debe colocar en la linea que une al rival con el centro de nuestra porteria y a la distancia_marcaje del rival

		for (int i = 1; i < CTE.NUM_JUGADORES; i++) {
			if (marcajes.estaMarcando(i)) {
				posRival = eqRival.posActual[marcajes.jugadorMarcado(i)];
				posMarcaje = posRival.moverAngulo(posRival.angulo(Constantes.centroArcoInf), CTE.DIST_MARCAJE);
				comandos.add(new ComandoIrA(i, posMarcaje));
			}
		}
	}
	
	
	
	private void anadirComandosMolestarNoMarcados()
	{
		// buscar a los que no estan marcados y marcarlos 
	}
	
	
	
	/**
	 * metodo antiguo
	 * @param jugPasador
	 * @param jugFuturo
	 */
	private void anadirComandosPaseSimple(int jugPasador, int jugFuturo)
	{
		Posicion posJugFuturo = eqMio.posActual[jugFuturo];
		double distBalonDestino = posBalonActual.distancia(posJugFuturo);
		DoubleDouble parFuerzaAngulo = (eqMio.posActual[jugPasador].getY() < posJugFuturo.getY())
			? TIROS_ALTOS.getTiro(distBalonDestino) : TIROS_ALTOS.getPaseAlto(distBalonDestino);
		Posicion posDestino = posJugFuturo.moverPosicion(0, 4);
		
		//log.info(jugPasador + "->" +jugFuturo + "  " + posDestino);

		if (parFuerzaAngulo == null) {
			anadirGolpeo(new ComandoGolpearBalon(jugPasador, posDestino, 1.0, 40.0));
		}
		else {
			anadirGolpeo(new ComandoGolpearBalon(jugPasador, posDestino, parFuerzaAngulo.double1, parFuerzaAngulo.double2));
		}
		// el jugador que debe recibir lo acercamos
		comandos.add(new ComandoIrA(jugFuturo, posDestino));
		// luego al al calcular la nueva trayectoria se acercara mas y con exactitud

		progMovJug = null;
	}
	
	
	
	private void anadirComandosPaseAnalizado(int jugPasador, PaseAnalizado gt)
	{
		//log.info("!");
		
		anadirGolpeo(new ComandoGolpearBalon(jugPasador, gt.posicion, 1.0, gt.angVertical));
		
		// acercamos a todos los jugadores (paso de calcular quien la puede recibir)
		for (int i = 0; i < CTE.NUM_JUGADORES; i++) {
			if (i != jugPasador) {
				comandos.add(new ComandoIrA(i, gt.posicion));
			}
		}
		
		progMovJug = null;
	}
	
	
	
	private void anadirComandosAvanzar(int jugador, Posicion posDestino)
	{
		//log.info("!  j=" + jugador + "  pos=" + posDestino);
		comandos.add(new ComandoIrA(jugador, posDestino));
		anadirGolpeo(new ComandoGolpearBalon(jugador));
		
		progMovJug = new ProgramaMovimientoJugador(jugador, posDestino);

		// buscamos a otro jugador que este cerca del balon, por si puede llegar que llegue antes
		Posicion posIntermedia = Posicion.media(posBalonActual, posDestino);
		int jugCercano = posIntermedia.indiceMasCercano(eqMio.posActual, jugador);
		comandos.add(new ComandoIrA(jugCercano, posIntermedia));
	}
	
	

	
	private void anadirComandosTiro(int jugador)
	{
		// calculamos el mejor angulo
		double angDisparo = calcularAnguloDisparo();
		// calculo donde teoricamente va a ser gol
		Posicion posGol = getInterseccion(posBalonActual, angDisparo, Constantes.posteIzqArcoSup, Constantes.posteDerArcoSup);
		// calculamos el mejor angulo vertical para ese angulo (que implica una distancia distinta que el centro de la porteria)
		double distLineaGol = posGol.distancia(posGol);
		double mejorAngVertical = TIROS_ALTOS.getAnguloVerticalTiroRaso(distLineaGol);
		
		//log.info("!  j=" + jugador + "  ang=" + mejorAngVertical + "  dist=" + distBalonPorteria);
		anadirGolpeo(new ComandoGolpearBalon(jugador, angDisparo, 1.0, mejorAngVertical));

		progMovJug = null;
	}

	
	
	private void anadirComandosTiroLejano(int jugador)
	{
		//log.info("!  " + jugador);

		anadirGolpeo(new ComandoGolpearBalon(jugador, CTE.PTO_CENTRO_PORTERIA_RIVAL, 1.0, 30.0));

		progMovJug = null;
	}


	
	
	private void anadirComandosDespejar(int jugador)
	{
		//log.info("!  " + jugador);

		anadirGolpeo(new ComandoGolpearBalon(jugador, 90.0, 1.0, 30.0));
		
		progMovJug = null;
	}


	
	public void anadirGolpeo(ComandoGolpearBalon comando)
	{
		for (int i = 0; i < CTE.ITERACIONES; i++) comandos.add(comando);

		eqMio.setUltimoGolpeo(comando.getIndJugador());
		balonGolpeado = true;
		golpeeYo = true;
		ultimoGolpeo = new UltimoGolpeo(comando.getIndJugador(), posBalonActual, comando.getDestinoBalon());
	}
	
	
	
	////////////////////////////////////////////////////////////////////////
	// METODOS DE AYUDA ////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////


	/**
	 * calcula el mejor angulo de disparo
	 */
	private double calcularAnguloDisparo()
	{
		double angBalonPosteIzq = posBalonActual.angulo(Constantes.posteIzqArcoSup);
		double angBalonPosteDer = posBalonActual.angulo(Constantes.posteDerArcoSup);
		double angBalonPorteroRival = posBalonActual.angulo(eqRival.posActual[eqRival.indicePortero]);
		double angulo = angBalonPorteroRival;
		
		if (Util.estaEn(angBalonPorteroRival, angBalonPosteDer, angBalonPosteIzq)) {
			// el portero esta dentro del triangulo formado por el balon y los postes
			double angEspacioDer = angBalonPorteroRival - angBalonPosteDer;
			double angEspacioIzq = angBalonPosteIzq - angBalonPorteroRival;

			if (angEspacioDer > angEspacioIzq) {
				angulo = angBalonPosteDer + angEspacioDer / 3;
			}
			else if (angEspacioIzq > angEspacioDer) {
				angulo = angBalonPosteIzq - angEspacioIzq / 3;
			}
			else {
				// angulos iguales
				double distBalonPosteIzq = posBalonActual.norma(Constantes.posteIzqArcoSup);
				double distBalonPosteDer = posBalonActual.norma(Constantes.posteDerArcoSup);
				if (distBalonPosteDer < distBalonPosteIzq) {
					angulo = angBalonPosteDer + angEspacioDer / 3;
				}
				else {
					angulo = angBalonPosteIzq - angEspacioIzq / 3;
				}
			}
		}
		else {
			// el portero esta fuera del triangulo formado por el balon y los postes, tiramos al centro de la porteria
			angulo = posBalonActual.angulo(CTE.PTO_CENTRO_PORTERIA_RIVAL);
		}
		
		return Math.toDegrees(angulo);
	}
	
	
	
	/**
	 * Partimos de la posicion del balon y el jugador que golpea.
	 * Se generan los golpeos en el abanico de 80� en direccion a la porteria.
	 * Nos quedamos con el avance que nos deja mas cerca de la porteria
	 */
	private Posicion calcularPosicionAvance(Posicion posBalon, int jugador)
	{
		final int[] MULT_INCR_ANGULO = new int[] {0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, -9, 9, -10 , 10,
				 -11, 11, -12, 12, -13, 13, -14, 14, -15, 15, -16, 16, -17, 17, -18};
		final double INCR_ANGULO = Math.toRadians(10);
		double ANGULO_BASE = posBalon.angulo(CTE.PTO_CENTRO_PORTERIA_RIVAL);
		double angulo;
		Posicion posAvance;
		
		//log.info("!");
		
		for (int i = 0; i < MULT_INCR_ANGULO.length; i++) {
			// calculamos el angulo
			angulo = MULT_INCR_ANGULO[i] * INCR_ANGULO + ANGULO_BASE;
			////log.info("i=" + i + "   angulo=" + angulo);
			if (esAvanceSeguro(posBalon, angulo, jugador)) {
				////log.info("avance seguro");
				posAvance = posBalon.moverAngulo(angulo, CTE.DIST_AVANCE_SEGURO);
				return posAvance;
			}
		}
		return null;
	}
	

	
	private boolean esAvanceSeguro(Posicion posBalon, double angulo, int jugadorGolpea)
	{
		Boolean avanceSeguro = null;
		Posicion posFutura;
		PosicionBalon posBalFutura;
		ProgramaMovimientoJugador mio, rival;
		int iMas1;
		
		// guardamos golpeos
		int golpeosJugGolpea = eqMio.ultimoGolpeo[jugadorGolpea]; 
		eqMio.ultimoGolpeo[jugadorGolpea] = iteracionPartido;
		
		for (int i = 0; avanceSeguro == null && i < CTE.DIST_BALON_AVANZAR.length; i++) {
			iMas1 = i+1;
			posFutura = posBalon.moverAngulo(angulo, CTE.DIST_BALON_AVANZAR[i]);
			posBalFutura = new PosicionBalon(posFutura);
			////log.info("i=" + iMas1 + "   dist=" + CTE.DIST_BALON_AVANZAR[i] + "  pos=" + posFutura);
			if (Util.estaEnCampo(posFutura)) {
				mio = calcularMejoresJugadores(posBalFutura, eqMio, iteracionPartido, iteracionPartido+iMas1)[TODOS];
				rival = calcularMejoresJugadores(posBalFutura, eqRival, iteracionPartido, iteracionPartido+iMas1)[TODOS];
				
				if (rival.iteracionesHastaPosicion <= iMas1) {
					avanceSeguro = Boolean.FALSE;
				}
				else if (mio.iteracionesHastaPosicion < iMas1 &&
						mio.iteracionesHastaPosicion <= rival.iteracionesHastaPosicion - 2) {
					avanceSeguro = Boolean.TRUE;
				}
				
//				if (rival.iteracionesHastaPosicion <= iMas1 && mio.iteracionesHastaPosicion > iMas1 || 
//						mio.iteracionesHastaPosicion <= iMas1 && rival.iteracionesHastaPosicion <= iMas1) {
//					avanceSeguro = Boolean.FALSE;
//				}
//				else if (mio.iteracionesHastaPosicion <= iMas1 && rival.iteracionesHastaPosicion > iMas1 && 
//						mio.iteracionesHastaPosicion <= rival.iteracionesHastaPosicion - 2) {
//					avanceSeguro = Boolean.TRUE;
//				}
			}
			else {
				avanceSeguro = Boolean.FALSE;
			}
		}
		
		// restauramos golpeos
		eqMio.ultimoGolpeo[jugadorGolpea] = golpeosJugGolpea;
		
		return (avanceSeguro != null) ? avanceSeguro.booleanValue() : false;
	}

	
	
	private ProgramaMovimientoJugador taparSaque(Posicion posSaque, Posicion[] posiciones)
	{
		ProgramaMovimientoJugador progMovJug = null;
		Posicion posJugadorDestino;
		int jugador;
		double signo;
		
		if (posSaque.getY() >= 45 && Math.abs(posSaque.getX()) < 12) { 
			// fuera, saque de puerta rival
			signo = Math.signum(posSaque.getX());
			jugador = posSaque.indiceMasCercano(posiciones);
			posJugadorDestino = new Posicion(signo * CTE.POS_X_ABS_SAQUE_PUERTA, CTE.POS_Y_SAQUE_PUERTA);
			progMovJug = new ProgramaMovimientoJugador(jugador, posJugadorDestino);
		}
		else if (Math.abs(posSaque.getX()) >= CTE.MITAD_ANCHO_CAMPO) {
			// saque de banda
			signo = Math.signum(posSaque.getX());
			double distTaparX = -signo * CTE.DIST_TAPAR_SAQUE;
			double distTaparY = (posSaque.getY() > 0) ? - CTE.DIST_TAPAR_SAQUE : 0;
			posJugadorDestino = new Posicion(signo * CTE.MITAD_ANCHO_CAMPO + distTaparX, posSaque.getY() + distTaparY);
			jugador = posSaque.indiceMasCercano(posiciones);
			progMovJug = new ProgramaMovimientoJugador(jugador, posJugadorDestino);
		}
		
		return progMovJug;
	}
	
	
	
	/**
	 * Calcula el jugador mejor situado para para una posicion (el que llega antes a una posicion)
	 * tiene en cuenta los ultimos golpeos y las iteraciones
	 *
	 * posBalon = posicion del balon en el futuro
	 * infoEquipo = informacion del equipo
	 * iteracionBase = iteracion en la que se esta calculando
	 * iteracion = iteracion que se esta simulando
	 * 
	 * return: 0=tiene en cuenta al portero ; 1=no tiene en cuenta al portero
	 */
	private ProgramaMovimientoJugador[] calcularMejoresJugadores(
			PosicionBalon posBalon, 
			InfoEquipo infoEquipo,
			int iteracionBase,
			int iteracionSimulada)
	{
		double distJugBalon, distControl, alturaControl;
		ProgramaMovimientoJugador mejorNP = new ProgramaMovimientoJugador(99999, 99999, 99999);	// no portero
		ProgramaMovimientoJugador mejor = new ProgramaMovimientoJugador(99999, 99999, 99999);
		int iteracionesToPosicion;
		boolean checkJugador, controlable;
		
		if (!posBalon.isParablePortero()) {
			return null;
		}
		////log.info("iteracion=" + iteracion + "   ultimo golpeo=" + ultimoGolpeo);

		for (int i = 0; i < infoEquipo.posActual.length; i++) {
			// miramos si el jugador puede golpear
			checkJugador = iteracionSimulada > infoEquipo.ultimoGolpeo[i] + Constantes.ITERACIONES_GOLPEAR_BALON; 
			if (checkJugador) {
				// si puede golpear
				distControl = (i != infoEquipo.indicePortero) ? Constantes.DISTANCIA_CONTROL_BALON : Constantes.DISTANCIA_CONTROL_BALON_PORTERO;
				alturaControl = (i != infoEquipo.indicePortero) ? Constantes.ALTURA_CONTROL_BALON : Constantes.ALTO_ARCO;
				controlable = posBalon.getZ() <= alturaControl; 
				distJugBalon = infoEquipo.posActual[i].distancia(posBalon.getPosicion()) - distControl + CTE.AJUSTE_DIST_CONTROL_BALON; // introducimos un peque�o error
				iteracionesToPosicion = new Double(Math.ceil(distJugBalon / infoEquipo.velocidad[i])).intValue();
				
				if (iteracionesToPosicion <= mejor.iteracionesHastaPosicion && controlable) {
					mejor.iteracionesHastaPosicion = iteracionesToPosicion;
					mejor.jugador = i;
					mejor.posicionDestino = posBalon.getPosicion();
				}
				if (iteracionesToPosicion <= mejorNP.iteracionesHastaPosicion && i != infoEquipo.indicePortero && controlable) {
					mejorNP.iteracionesHastaPosicion = iteracionesToPosicion;
					mejorNP.jugador = i;
					mejorNP.posicionDestino = posBalon.getPosicion();
				}
				
			}
		}
		
		return new ProgramaMovimientoJugador[] {mejor, mejorNP};
	}

	
	
	
	/**
	 * mira si solo un jugador tienen el balon
	 * el jugador debe pertenecer al eq 1
	 * @param puedenRematarEq1
	 * @param puedenRematarEq2
	 * @return
	 */
	private int getJugTieneBalon(int[] puedenRematarEq1, int[] puedenRematarEq2)
	{
		if (puedenRematarEq1.length > puedenRematarEq2.length 
			&& puedenRematarEq2.length == 0) {
			return puedenRematarEq1[0];
		}
		else {
			return -1;
		}
	}
	
	
	
	
	/**
	 * calcula el jugador
	 * @param numPasador
	 * @param errorPasador
	 * @return
	 */
	private int buscarPaseFacil(int numPasador, boolean permitirPaseAtras)
	{
		int mejorJugador = -1;
		int menosRivales = 1000;
		double mejorY = 1000;
		
		double distJugJug;
		Polygon pol;
		int rivales;
		double margenPaseAtras;
		
		for (int i = 1; i < CTE.NUM_JUGADORES; i++) {
			margenPaseAtras = (permitirPaseAtras) ? CTE.MARGEN_MAX_PASE_ATRAS : CTE.MARGEN_PASE_ATRAS;
			if (i != numPasador && eqMio.posActual[numPasador].getY() < eqMio.posActual[i].getY() + margenPaseAtras) {
				distJugJug = eqMio.posActual[numPasador].distancia(eqMio.posActual[i]);
				if (distJugJug < 40) { // distancia fiable
					pol = crearZona(eqMio.posActual[i], distJugJug / 5);
					rivales = cuantosHayEnZona(pol, eqRival.posActual);
					if (rivales <= menosRivales) {
						if (rivales < menosRivales) {
							mejorJugador = i;
						}
						else if (eqMio.posActual[numPasador].getY() > mejorY) {
							mejorJugador = i;
						}
						mejorY = eqMio.posActual[numPasador].getY();
					}
				}
			}
		}
		
		return (mejorJugador > 0) ? mejorJugador : -1;
	}
	
	
	
	///////////////////////////////////////////////////////////////////////////
	// ANALISIS DE PASES
	///////////////////////////////////////////////////////////////////////////
	
	
	final double INCR_ANG_HOR = 2.8; // en grados
	final int ANG_HORIZONTALES = (int) (360d / INCR_ANG_HOR) + 1;
	final double[] ANG_VERT_ANALISIS = new double[] {25d, 35d, 45d};
	double[] angHorAnalisis = new double[ANG_HORIZONTALES];
	TrayectoriaBalon[][] precalculoTrayectoriaRotada = new TrayectoriaBalon[ANG_VERT_ANALISIS.length][ANG_HORIZONTALES];
		
	
	/**
	 * Devuelve el pase con mas posibilidades de exito
	 * @param jugador
	 */
	public PaseAnalizado buscarMejorPase(int jugador, double angMirada)
	{
		double mitadAmplitudAngJug = Constantes.getErrorAngular(eqMio.precision[jugador]) / 2;
		Posicion posCoger;
		boolean trayectoriaFavorable;
		TrayectoriaBalon trayectoriaRotada;
		List<PosicionBalon> posicionesTransformadas;
		TrayectoriaAnalizada trayectoriaAnalizada;
		List<TrayectoriaAnalizada> listTrayectoriasAnalizadas;
		List<PaseAnalizado> listPasesAnalizados;
		boolean[] analizarAng = new boolean[ANG_HORIZONTALES];
		
		double angIni = Util.normalizarAngulo(angMirada - CTE.ANG_90 - mitadAmplitudAngJug);
		double angFin = Util.normalizarAngulo(angMirada + CTE.ANG_90 + mitadAmplitudAngJug);

		// generamos los angulos horizontales para trabajar
//		for (int a = 0; a < ANG_HORIZONTALES; a++) {
//			angHorAnalisis[a] = Math.toRadians(INCR_ANG_HOR * a);
//			//log.info(a+"="+angHorAnalisis[a]);
//		}

		
		for (int i = 0; i < ANG_HORIZONTALES; i++) {
			analizarAng[i] = Util.anguloEstaEn(angHorAnalisis[i], angIni, angFin);
		}
		
		listTrayectoriasAnalizadas = new ArrayList<TrayectoriaAnalizada>(ANG_HORIZONTALES * ANG_VERT_ANALISIS.length);
		listPasesAnalizados = new ArrayList<PaseAnalizado>(ANG_HORIZONTALES * ANG_VERT_ANALISIS.length);

		// generamos todas las combinaciones de pase
		for (int i = 0; i < ANG_VERT_ANALISIS.length; i++) { // angulos verticales
			for (int j = 0; j < ANG_HORIZONTALES; j++) {
				if (analizarAng[i]) {
					trayectoriaRotada = precalculoTrayectoriaRotada[i][j];
					posicionesTransformadas = desplazarTrayectoria(trayectoriaRotada, posBalonActual);
					posCoger = esTrayectoriaFavorable(jugador, posicionesTransformadas);
					trayectoriaFavorable = posCoger != null;
					if (posCoger == null) { // si no tiene posicion donde cogera el balon, le ponemos una a groso modo
						posCoger = posBalonActual.moverAngulo(angHorAnalisis[j], 30);
					}
					trayectoriaAnalizada = new TrayectoriaAnalizada(angHorAnalisis[j], ANG_VERT_ANALISIS[i], trayectoriaFavorable, posCoger);
					//log.info("trayectoria: " + trayectoriaAnalizada);
					listTrayectoriasAnalizadas.add(trayectoriaAnalizada);
				}
			}
		}
		
		// examinamos
		for (TrayectoriaAnalizada at: listTrayectoriasAnalizadas) {
			if (Util.anguloEstaEn(at.angHorizontal, angIni, angFin)) {
				listPasesAnalizados.add(analizarPase(listTrayectoriasAnalizadas, at, mitadAmplitudAngJug));
			}
		}
		
		// buscamos la mejor
		PaseAnalizado mejorPase = new PaseAnalizado(0,0,0,0,Constantes.centroCampoJuego);
		
		for (PaseAnalizado paseAnalizado: listPasesAnalizados) {
			if (paseAnalizado.esMejorQue(mejorPase)) {
				mejorPase = paseAnalizado;
			}
			
		}
		//log.info("mejor pase: " + mejorPase);
		
		return (mejorPase.casos > 0) ? mejorPase : null;
	}

	
	
	
	private PaseAnalizado analizarPase(List<TrayectoriaAnalizada> aatt, TrayectoriaAnalizada at, double mitadAmplitudAngJug)
	{
		//log.info(at.toString());
		
		double angIni = at.angHorizontal - mitadAmplitudAngJug - 0.0001;
		double angFin = at.angHorizontal + mitadAmplitudAngJug + 0.0001;
		int favor = 0, contra = 0;
		
		for (TrayectoriaAnalizada at2: aatt) {
			if (at2.angVertical == at.angVertical && Util.anguloEstaEn(at2.angHorizontal, angIni, angFin)) {
				//log.info("        " + at2.toString());
				if (at2.favorable) {
					favor++;
				}
				else {
					contra++;
				}
			}
		}
		//log.info("    --->" + new PaseAnalizado(at, favor, contra));
		return new PaseAnalizado(at, favor, contra);
	}

	
	
	/**
	 * desplaza todos los puntos de la trayectoria al punto posOrigen como origen (antes era 0,0)
	 * @param trayectoria trayectoria rotada en el origen (0,0)
	 * @param posOrigen posicion a la que se desplazara
	 * @return
	 */
	private List<PosicionBalon> desplazarTrayectoria(TrayectoriaBalon trayectoria, Posicion posOrigen)
	{
		List<PosicionBalon> posiciones = trayectoria.getPosiciones();
		List<PosicionBalon> posicionesDesplazadas = new ArrayList<PosicionBalon>(posiciones.size());
		
		for (PosicionBalon posicionBalon: posiciones) {
			posicionesDesplazadas.add(new PosicionBalon(posicionBalon.getPosicion().moverPosicion(posOrigen.getX(), posOrigen.getY()), 
					                                    posicionBalon.getZ()));
		}
		
		return posicionesDesplazadas;
	}

	
	
	/**
	 * 
	 * @param jugador
	 * @param posiciones
	 * @return si la trayectoria es favorable devuelve la posicion en la que podemos coger el balon
	 */
	private Posicion esTrayectoriaFavorable(int jugador, List<PosicionBalon> posiciones)
	{
		PosicionBalon posBalon;
		Posicion posCogerBalon = null;
		ProgramaMovimientoJugador mio, rival;
		int iMas1;
		boolean fin = false;
		
		// guardamos
		int golpeosJugador = eqMio.ultimoGolpeo[jugador];
		eqMio.ultimoGolpeo[jugador] = iteracionPartido;

		for (int i = 0; !fin && i < posiciones.size(); i++) {
			iMas1 = i+1;
			posBalon = posiciones.get(i);
			if (posBalon.isDentroCampo()) {
				if (posBalon.isJugable()) {
					mio = calcularMejoresJugadores(posBalon, eqMio, iteracionPartido, iteracionPartido+i+1)[TODOS];
					rival = calcularMejoresJugadores(posBalon, eqRival, iteracionPartido, iteracionPartido+i+1)[TODOS];
					
					if (rival.iteracionesHastaPosicion <= iMas1) {
						fin = true;
					}
					else if (mio.iteracionesHastaPosicion <= iMas1) {
						fin = true;
						posCogerBalon = posBalon.getPosicion();
					}
					
//					if (rival.iteracionesHastaPosicion <= iMas1 && mio.iteracionesHastaPosicion > iMas1 ||
//							mio.iteracionesHastaPosicion <= iMas1 && rival.iteracionesHastaPosicion <= iMas1) {
//						fin = true;
//					}
//					else if (mio.iteracionesHastaPosicion <= iMas1 && rival.iteracionesHastaPosicion > iMas1 &&
//							mio.iteracionesHastaPosicion <= rival.iteracionesHastaPosicion - 2) {
//						fin = true;
//						posCogerBalon = posBalon.getPosicion();
//					}
				}
			}
		}
		
		// restauramos
		eqMio.ultimoGolpeo[jugador] = golpeosJugador;
		
		return posCogerBalon;
	}

	
	
	/**
	 * precalculos
	 */
	private void precalcularTrayectorias()
	{
		// angulos horizontales
		for (int a = 0; a < ANG_HORIZONTALES; a++) {
			angHorAnalisis[a] = Math.toRadians(INCR_ANG_HOR * a);
			//log.info(a+"="+angHorAnalisis[a]);
		}
		
		// precalculos trayectorias rotadas
		Posicion posDestino;
		for (int v = 0; v < ANG_VERT_ANALISIS.length; v++) {
			for (int h = 0; h < ANG_HORIZONTALES; h++) {
				posDestino = Constantes.centroCampoJuego.moverAngulo(angHorAnalisis[h], 30);
				precalculoTrayectoriaRotada[v][h] = new TrayectoriaBalon(1.0, ANG_VERT_ANALISIS[v], Constantes.centroCampoJuego, posDestino);
			}
		}
		
	}
	
	


	////////////////// AYUDAS A LA TACTICA //////////////////
	
	
	private boolean sobreElBalon(InfoEquipo infoEquipo, Posicion posBalon)
	{
		int jug = posBalon.indiceMasCercano(infoEquipo.posActual);
		double dist = (jug == infoEquipo.indicePortero) ? Constantes.DISTANCIA_CONTROL_BALON_PORTERO : Constantes.DISTANCIA_CONTROL_BALON;
		
		return infoEquipo.posActual[jug].distancia(posBalon) <= dist;
	}
	

	/**
	 * obtiene la interseccion de las rectas dadas por (posicion,angulo) y (punto1,punto2)
	 * @param posicion
	 * @param angulo
	 * @param punto1
	 * @param punto2
	 * @return
	 */
	private Posicion getInterseccion(Posicion posicion, double angulo, Posicion punto1, Posicion punto2)
	{
		Posicion posAux = posicion.moverAngulo(angulo, 200);
		
		return Posicion.Interseccion(posicion, posAux, punto1, punto2);
	}

	
	
	private boolean buenAnguloTiro()
	{
		return Util.anguloEstaEn(posBalonActual.angulo(CTE.PTO_CENTRO_PORTERIA_RIVAL), CTE.ANG_DISPARO_MIN, CTE.ANG_DISPARO_MAX);
	}
	
	
	
	private boolean isPartidoFavorable()
	{
		return (eqMio.goles > eqRival.goles) || (eqMio.goles == eqRival.goles && eqMio.posesion > eqRival.posesion); 
	}
	
	
	
	/**
	 * Calcula si el valon va dirigido a la porteria
	 * @param ptoOrigen pos del balon
	 * @param angDireccion angulo de la direccion del balon
	 * @return
	 */
	private boolean direccionGol(Posicion ptoOrigen, double angDireccion)
	{
		boolean dirGol = false;
		
		try {
			Posicion posGol = getInterseccion(ptoOrigen, angDireccion, Constantes.posteIzqArcoInf, Constantes.posteDerArcoInf);
			dirGol = Util.estaEn(posGol.getX(), Constantes.posteIzqArcoInf.getX(), Constantes.posteDerArcoInf.getX());
		}
		catch (Exception e) {}
		
		return dirGol;
	}
	
	
	
	private boolean balonCasiParado(Posicion posAnt, Posicion posAct)
	{
		return posAnt != null && posAnt.distancia(posAct) < CTE.DIST_BALON_CASI_PARADO;
	}
	
	
	
	//
	
	
	/**
	 * Crea una zona circular (+ o -) sobre un punto
	 * @param pos
	 * @param radio
	 * @return
	 */
	private Polygon crearZona(Posicion pos, double radio)
	{
		Polygon circulo = new Polygon();
		double px, py;
		
		for (double angulo = 0; angulo < 2 * Math.PI; angulo += Math.PI / 8) {
			px = Math.cos(angulo) * radio + pos.getX();
			py = Math.sin(angulo) * radio + pos.getY();
			circulo.addPoint((int) px, (int) py);
		}
		
		return circulo;
	}
	

	/**
	 * cuenta cuantos jugadores estan en la zona
	 * @param zona
	 * @param posJug
	 * @return
	 */
	private int cuantosHayEnZona(Polygon zona, Posicion[] posJug)
	{
		int cuantos = 0;
		
		for (int i = 0; i < posJug.length; i++) {
			if (zona.contains(Util.toPoint(posJug[i]))) {
				cuantos++;
			}
		}
		
		return cuantos;
	}
	
	
}
